package main

import (
	"encoding/json"
	"fmt"
	"github.com/hyperledger/fabric-contract-api-go/contractapi"
	"log"
	"time"
)

// SmartContract provides functions for managing an Asset
type SmartContract struct {
	contractapi.Contract
}

// Log Asset describes basic details of what makes up a simple asset
type Policy_ledger struct {
	Owner      string `json:"PK_DS"`  //数据拥有者
	Controller string `json:"PK_DC"`  //数据控制者即服务提供者
	Time       string `json:"ts"`     //时间戳
	Policy     string `json:"policy"` //数据控制者的权限
}

// InitLedger adds a base set of assets to the ledger
func (s *SmartContract) InitLedger(ctx contractapi.TransactionContextInterface) error {
	policy1 := []string{"add", "update"}
	policyasbytes, _ := json.Marshal(policy1)
	t := time.Now() //当前时间
	timeLayoutStr := "2006-01-02 15:04:05"
	timenow := t.Format(timeLayoutStr)
	policyLedgers := []Policy_ledger{
		{Owner: "002", Controller: "001", Time: timenow, Policy: string(policyasbytes)},
		{Owner: "003", Controller: "001", Time: timenow, Policy: string(policyasbytes)},
		{Owner: "004", Controller: "001", Time: timenow, Policy: string(policyasbytes)},
		{Owner: "005", Controller: "001", Time: timenow, Policy: string(policyasbytes)},
		{Owner: "006", Controller: "001", Time: timenow, Policy: string(policyasbytes)},
	}
	pl := Policy_ledger{}
	pl.Time = timenow
	pl.Policy = string(policyasbytes)
	// log1 := Log{}
	// log1.Owner = "111"
	// log1.Processor = "222"
	// log1.Controller = "333"
	// log1.Policy = string(policyasbytes)
	// assets = append(assets, log1)

	//err1 = ctx.GetStub().
	for _, policyLedger := range policyLedgers {
		assetJSON, err := json.Marshal(policyLedger)
		if err != nil {
			return err
		}
		//err = ctx.GetStub().
		err = ctx.GetStub().PutState(policyLedger.Owner+policyLedger.Controller, assetJSON)
		if err != nil {
			return fmt.Errorf("failed to put to world state. %v", err)
		}
	}

	return nil
}


// GrantConsent adds a base set of assets to the ledger
func (s *SmartContract) GrantConsent(ctx contractapi.TransactionContextInterface, owner string, controller string, op string) string {
	value, err := ctx.GetStub().GetState(owner + controller)
	if err != nil {
		return ("invalid Smart Contract function name")
	}
	if value == nil {
		policy1 := []string{}
		policy1 = append(policy1, op)
		policyasbytes, _ := json.Marshal(policy1)
		t := time.Now() //当前时间
		timeLayoutStr := "2006-01-02 15:04:05"
		timenow := t.Format(timeLayoutStr)
		pl := Policy_ledger{}
		pl.Owner = owner
		pl.Controller = controller
		pl.Time = timenow
		pl.Policy = string(policyasbytes)
		plJSON, _ := json.Marshal(pl)
		_ = ctx.GetStub().PutState(pl.Owner+pl.Controller, plJSON)
		return string(plJSON)
	} else {
		pl := Policy_ledger{}
		err = json.Unmarshal(value, &pl)
		if err != nil {
			return ("No log")
		}
		po := pl.Policy
		po1 := []string{}
		err = json.Unmarshal([]byte(po), &po1)
		i := 0
		for i = 0; i < len(po1); i++ {
			if op == po1[i] {
				break
			}
		}
		if i == len(po1) {
			po1 = append(po1, op)
			_ = ctx.GetStub().DelState(pl.Owner + pl.Controller)
			//_ = ctx.GetStub().PutState(pl.Owner+pl.Controller, plJSON)
			policyasbytes, _ := json.Marshal(po1)
			t := time.Now() //当前时间
			timeLayoutStr := "2006-01-02 15:04:05"
			timenow := t.Format(timeLayoutStr)
			pl := Policy_ledger{}
			pl.Owner = owner
			pl.Controller = controller
			pl.Time = timenow
			pl.Policy = string(policyasbytes)
			plJSON, _ := json.Marshal(pl)
			_ = ctx.GetStub().PutState(pl.Owner+pl.Controller, plJSON)
			return string(plJSON)
		} else {
			return "op already exist"
		}
	}

}

func (s *SmartContract) RevokeConsent(ctx contractapi.TransactionContextInterface, owner string, controller string, op string) string {
	value, err := ctx.GetStub().GetState(owner + controller)
	if err != nil {
		return ("invalid Smart Contract function name")
	}
	if value == nil {
		return "no key in 3A"
	} else {
		pl := Policy_ledger{}
		err = json.Unmarshal(value, &pl)
		if err != nil {
			return ("No log")
		}
		po := pl.Policy
		po1 := []string{}
		err = json.Unmarshal([]byte(po), &po1)
		i := 0
		for i = 0; i < len(po1); i++ {
			if op == po1[i] {
				po1 = append(po1[:i],po1[i+1:]...)
				_ = ctx.GetStub().DelState(pl.Owner + pl.Controller)
				//_ = ctx.GetStub().PutState(pl.Owner+pl.Controller, plJSON)
				policyasbytes, _ := json.Marshal(po1)
				t := time.Now() //当前时间
				timeLayoutStr := "2006-01-02 15:04:05"
				timenow := t.Format(timeLayoutStr)
				pl := Policy_ledger{}
				pl.Owner = owner
				pl.Controller = controller
				pl.Time = timenow
				pl.Policy = string(policyasbytes)
				plJSON, _ := json.Marshal(pl)
				_ = ctx.GetStub().PutState(pl.Owner+pl.Controller, plJSON)
				return string(plJSON)
				break
			}
		}
		if i == len(po1) {

			return "on op"
		} else {
			return "op delete success"
		}
	}

}

func (s *SmartContract) DataAccess(ctx contractapi.TransactionContextInterface, owner string, controller string, op string) string {
	value, err := ctx.GetStub().GetState(owner + controller)
	if err != nil {
		return ("invalid Smart Contract function name")
	}
	if value == nil {

		return "no 3A"
	} else {
		pl := Policy_ledger{}
		err = json.Unmarshal(value, &pl)
		if err != nil {
			return ("No log")
		}
		po := pl.Policy
		po1 := []string{}
		err = json.Unmarshal([]byte(po), &po1)
		i := 0
		for i = 0; i < len(po1); i++ {
			if op == po1[i] {
				break
			}
		}
		if i == len(po1) {

			return "fail"
		} else {
			return "success"
		}
	}

}

func main() {
	assetChaincode, err := contractapi.NewChaincode(&SmartContract{})
	if err != nil {
		log.Panicf("Error creating asset-transfer-basic chaincode: %v", err)
	}

	if err := assetChaincode.Start(); err != nil {
		log.Panicf("Error starting asset-transfer-basic chaincode: %v", err)
	}
}